﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Cassandraemon
{
    internal static class CollectionExtensions
    {
        public static int GetSequenceHashCode<T>(this IEnumerable<T> obj)
        {
            int hash = 0;
            foreach (var item in obj)
            {
                hash = (hash << 1) ^ item.GetHashCode();
            }
            return hash;
        }

		public static bool SetEquals<T>(this IEnumerable<T> x, IEnumerable<T> y)
		{
			var setY = y as HashSet<T>;
			if (setY != null)
			{
				return setY.SetEquals(x);
			}

			var setX = x as HashSet<T>;
			if (setX == null)
			{
				setX = new HashSet<T>(x);
			}

			return setX.SetEquals(y);
		}
    }

    internal class SequenceComparer<T> :
        IEqualityComparer<T[]>
    {
        #region Constructors & Static Instances

        static readonly SequenceComparer<T> _Default = new SequenceComparer<T>();

        public static SequenceComparer<T> Default
        {
            get { return _Default; }
        }

        #endregion

        #region IEqualityComparer<T[]> Members

        public bool Equals(T[] x, T[] y)
        {
            return
                object.ReferenceEquals(x, y) ||
                (x != null && y != null && x.SequenceEqual(y));
        }

        public int GetHashCode(T[] obj)
        {
            return obj.GetSequenceHashCode();
        }

        #endregion
    }

	internal class SelectComparer<TSource, TResult> :
		IEqualityComparer<TSource>
	{
		#region Constructors

		public SelectComparer(
			Func<TSource, TResult> selector,
			IEqualityComparer<TResult> comparer)
		{
			this._Selector = selector;
			this._Comparer = comparer;
		}

		readonly Func<TSource, TResult> _Selector;
		readonly IEqualityComparer<TResult> _Comparer;

		#endregion

		#region IEqualityComparer<Column> Members

		public bool Equals(TSource x, TSource y)
		{
			if (object.ReferenceEquals(x, y)) { return true; }
			if (x == null || y == null) { return false; }

			var selector = this._Selector;
			var rx = selector(x);
			var ry = selector(y);
			return this._Comparer.Equals(rx, ry);
		}

		public int GetHashCode(TSource obj)
		{
			var r = this._Selector(obj);
			return this._Comparer.GetHashCode(r);
		}

		#endregion
	}
}
